package org.jinghouyu.caculator.engine.node;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.jinghouyu.caculator.engine.Expression;
import org.jinghouyu.caculator.engine.ExpressionContext;
import org.jinghouyu.caculator.engine.TextScanner;
import org.jinghouyu.caculator.engine.expression.MultiplyExpression;
import org.jinghouyu.caculator.engine.expression.MultiplyExpression.ByOneExpression;
import org.jinghouyu.caculator.engine.expression.PlusExpression;
import org.jinghouyu.caculator.engine.expression.PlusExpression.OneMunisExpression;

public class NodeParser {

	private static final Set<Character> symbols = new HashSet<>(Arrays.asList(new Character[]{'+','-','*','/'}));
	
	private static boolean isSymbol(String word) {
		if(word.length() != 1) return false;
		return symbols.contains(word.charAt(0));
	}
	
	public static Expression parse(String exp, ExpressionContext context) {
		Node[] nodes = NodeParser.parseNode(exp);
		List<SymbolNode> snodes = new ArrayList<>();
		List<Expression> exps = new ArrayList<>();
		//排序
		for(Node node : nodes) {
			if(node instanceof ParsableNode) {
				ParsableNode pnode = (ParsableNode) node;
				Expression expression = pnode.parse(context);
				exps.add(expression);
			} else {
				snodes.add((SymbolNode)node);
			}
		}
		return parse(snodes, exps);
	}
	
	private static Node[] parseNode(String expression) {
		TextScanner scanner = new TextScanner(expression);
		List<Node> nodes = new ArrayList<>();
		String word = null;
		while((word = scanner.nextWord()) != null) {
			if(isSymbol(word)) {
				nodes.add(new SymbolNode(word.charAt(0)));
			} else if(FunctionNode.isFunction(word)) {
				nodes.add(new FunctionNode(word));
			} else {
				nodes.add(new ExpressionNode(word));
			}
		}
		return nodes.toArray(new Node[]{});
	}
	
	//简单的四则运算
	private static Expression parse(List<SymbolNode> operators, List<Expression> operands) {
		if(operators.size() == 0) {
			return operands.get(0);
		}
		List<SymbolNode> nodes = new ArrayList<>();
		List<Expression> es = new ArrayList<>();
		Expression priorExpression = null;
		int i = 0;
		for(;i < operators.size(); i++) {
			SymbolNode opr = operators.get(i);
			if(opr.isDivide() || opr.isMulti()) {
				if(priorExpression == null) { //第一次
					priorExpression = new MultiplyExpression();
					priorExpression.addSubExpression(operands.get(i));
					if(opr.isDivide()) {
						priorExpression.addSubExpression(new ByOneExpression().addSubExpression(operands.get(i + 1)));
					} else {
						priorExpression.addSubExpression(operands.get(i + 1));
					}
				} else {
					if(opr.isDivide()) {
						priorExpression.addSubExpression(new ByOneExpression().addSubExpression(operands.get(i + 1)));
					} else {
						priorExpression.addSubExpression(operands.get(i + 1));
					}
				}
			} else {
				if(priorExpression != null) {
					es.add(priorExpression);
				} else {
					es.add(operands.get(i));
				}
				priorExpression = null;
				nodes.add(opr);
			}
		}
		if(priorExpression != null) {
			es.add(priorExpression);
		} else {
			es.add(operands.get(i));
		}
		
		Expression expression = new PlusExpression();
		for(i = 0; i < nodes.size(); i++) {
			SymbolNode node = nodes.get(i);
			if(i == 0) {
				expression.addSubExpression(es.get(i));
				if(node.isPlus()) {
					expression.addSubExpression(es.get(i + 1));
				} else {
					expression.addSubExpression(new OneMunisExpression().addSubExpression(es.get(i + 1)));
				}
			} else {
				if(node.isPlus()) {
					expression.addSubExpression(es.get(i + 1));
				} else {
					expression.addSubExpression(new OneMunisExpression().addSubExpression(es.get(i + 1)));
				}
			}
		}
		return expression;
	}
}
